package com.study.rpc.registry;

import com.study.rpc.protocol.InvokerProtocol;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author: huang
 * @Description TODO
 * @Date: 2021-01-16 19:42
 */
public class RegistryHandler extends ChannelInboundHandlerAdapter {

    private static ConcurrentHashMap<String,Object> registryMap = new ConcurrentHashMap<String,Object>();

    private List<String> classNames = new ArrayList<String>();

    public RegistryHandler(){
        scannerClass("com.study.rpc.provider");
        doRegister();
    }

    private void doRegister() {
        if(classNames.size()==0){
            return;
        }
        for (String className:classNames){
            try {
                Class<?> clazz = Class.forName(className);
                Class<?> i =  clazz.getInterfaces()[0];
                registryMap.put(i.getName(),clazz.newInstance());
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    private void scannerClass(String packageName) {
        URL url = this.getClass().getClassLoader().getResource(packageName.replaceAll("\\.","/"));
        assert url != null;
        File dir = new File(url.getFile());

        for (File file: Objects.requireNonNull(dir.listFiles())){
            if(file.isDirectory()){
                scannerClass(packageName+"."+file.getName());
            }else{
                classNames.add(packageName+"."+file.getName().replace(".class","").trim());
            }
        }
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Object result = new Object();
        InvokerProtocol request = (InvokerProtocol) msg;

        if(registryMap.containsKey(request.getClassName())){
            Object provider = registryMap.get(request.getClassName());
            Method method = provider.getClass().getMethod(request.getMethodName(),request.getParams());
            result = method.invoke(provider,request.getValues());
        }

        ctx.write(result);
        ctx.flush();
        ctx.close();
    }
}
